查看原文
其他

gh-ost 翻车!使用后导致数据丢失!

破产码农 InsideMySQL 2022-10-13
卡片,关注 InsideMySQL
相信对于很多 DBA 同学来说,由 Github 网站开源的在线 DDL 工具 gh-ost ,相信不会陌生。
对比另一款在线 DDL 工具 pt-osc,gh-ost 的开销更小。
gh-ost 通过二进制日志(binlog)记录 DDL 变更过程中的修改,而 pt-osc 通过触发器记录修改变化。
显然,触发器开销更大,且 5.7 版本之前一张表只能有一个类型的触发器,因此使用 pt-osc 的限制也更多些。
因此,使用工具 gh-ost 来进行在线表结构变更操作几乎可以认为是目前 MySQL 的一种标准变更规范
然而,gh-ost 翻车了!
在我们的生产环境中,使用 gh-ost 进行表结构变更后,导致了1条数据的丢失!
在金融业务中,数据丢失是绝对不容许发生的场景
我们的工程师同学经过周末连番的源码研究与测试,最终定位这的确是 gh-ost 代码 bug。
这意味着之前所有通过 gh-ost 进行 MySQL 数据库变更的操作,都有可能触发数据丢失。

复盘


接着,我给同学们复盘下使用 gh-ost 导致数据丢失的原因。
gh-ost 的基本实现原理如下图所示,具体实现不在本文章赘述,感兴趣的可移步官网:https://github.com/github/gh-ost

从源码实现的角度看,gh-ost 经历以下几个关键函数步骤:
1. addDMLEventsListener:添加对于二进制日志的过滤采集(指定表的二进制日志过滤)
2. ReadMigrationRangeValues:获取对应表唯一索引的max、min值
3. onBeforeRowCopy:将捕获的二进制日志应用到表 *_gho
4. iterateChunks:根据 min、max 值,批量插入数据到表 *_gho
5. rename & drop 新旧表
但是,存在一种可能性,addDMLEventListner后,对应的二进制日志“丢失”了!
这种情况发生的原因可能是因为 MySQL 数据库启用了 after_sync 模式的半同步复制。
怎么理解呢?可以通过下面的时序图来看:

从上图可以看到,在某些场景下,可能发生 gh-ost 开始捕获 DML 操作后的二进制日志,但是之前的二进制事务并没有提交!
在上图的案例中,步骤1 addDMLEventsListener 将会捕获记录5以后发生的日志。
然而,在步骤2 ReadMigrationRangeValues 中,获取 min、max的值将会是1、4。
这是因为由于 after_sync 半同步模式,记录5对应的事务还未提交(如网络原因,或从机宕机等场景),记录5对于 gh-ost 中的函数 ReadMigrationRangeValues  是不可见的。
因此,步骤3、4只会插入记录1-4,以及回放记录5之后的所有日志,但会丢失记录5。
既然知道了原因,那么修复就变得非常简单了。只需要在获取 min、max的边界值的时候通过一致性读取即可:
SELECT MIN(UK),MAX(UK) FROM xxxLOCK IN SHARE MODE;
通过 LOCK IN SHARE MODE,即便发生上述 after_sync 半同步等待问题,则在函数 ReadMigrationRangeValues 执行过程中,需要等待上述事务提交才能完成边界值的获取。
这时,边界值就会变为1、5,从而不会导致数据的丢失。

总结


从上述复盘看,gh-ost 数据丢失的可能性是比较大的,而且并不只是一条记录的丢失。
理论上可以是最后一组提交事务的数量,且每个事务可能影响的记录也不止一条。
反观工具 pt-osc,其通过触发器捕获增量日志,因此不存在该问题。
另一方面,从这个案例中可以看到一致性共享读取的使用场景。FOR UPDATE 的一致性排他读取大家都了解,但 LOCK IN SHARE MODE 何时使用呢?这个场景给了你很好的答案。
最后,在金融场景不能仅仅相信数据库的一致性检查。在上述场景下,主从数据核对检查依然是一致的,没有数据丢失。
所以,金融场景一定还要有业务层的数据核对,通过逻辑核对,确保数据库中的数据是没有任何物理丢失。
全文完,感谢你的耐心阅读。
微信平台改变了推送规则,如果你还想看到我的文章,请一定给本文“点赞”、“在看”、“分享” 三连,新文章推送才会第一时间出现在你的微信里。认识这么久,我可不想丢掉你。
每周五、六,不定期直播,分享技术干货


IMG群是码农的交流社区,IMG微信群交流内容包括但不限于技术、经济、军事、八卦等话题。欢迎有态度的码农们加入IMG大家庭。
IMG目前有少林群、武当群、峨眉群、华山群、M悦会(高端VIP群)
仅限码农入群,猎头或其他行业勿加,入群请加姜老师个人微信 82946772,并备注:码农入IMG群

往期推荐

央行官宣!开源软件即将迎来最好时代!

看看 Github 是如何升级最核心的数据库架构!

刚刚,我成功复活了 MySQL 祖先版本!

用 VSCode 编译和调试 MySQL,每个 DBA 都应 get 的小技能

收藏!最新《MySQL数据库开发设计规范》

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存